package com.ztesoft.book.api.config;

import com.ztesoft.book.common.constant.Constant;
import com.ztesoft.book.common.utils.http.HttpContextUtils;
import com.ztesoft.book.common.utils.http.IpUtils;
import com.ztesoft.book.common.utils.jwt.JwtUtil;
import com.ztesoft.book.core.sys.sysoperatelog.dto.SysOperateLogDTO;
import com.ztesoft.book.core.sys.sysoperatelog.mapper.SysOperateLogMapper;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.aop.support.AopUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

/**
 * 对重要表的增删改做aop拦截，并记录日志
 * author: mc
 * date: 2021-07-27
 */
@Aspect
@Component
@Slf4j
public class SysOperateAspect {

    @Resource
    private SysOperateLogMapper sysOperateLogMapper;

    @Pointcut("execution(* com.ztesoft.book.core.sys.sysuser.mapper.SysUserMapper.update*(..))")
    public void update() {
    }

    @Pointcut("execution(* com.ztesoft.book.core.sys.sysuser.mapper.SysUserMapper.delete*(..)) || " +
            "execution(* com.ztesoft.book.core.sys.sysuser.mapper.SysUserMapper.fakeDeleteByPrimaryKey(..))")
    public void delete() {
    }

    @Pointcut("execution(* com.ztesoft.book.core.sys.sysuser.mapper.SysUserMapper.insert*(..))")
    public void create() {
    }


    @Around(value = "update() || delete() || create()")
    @SneakyThrows
    public Object addLog(ProceedingJoinPoint joinPoint) {

        // 参数
        Object[] params = joinPoint.getArgs();


        // 获取表名
        Class<?> clazz = (Class<?>) AopUtils.getTargetClass(joinPoint.getTarget()).getGenericInterfaces()[0];
        String tableName = getTableName(clazz.getSimpleName());

        // 获取userId 和 ip
        HttpServletRequest httpServletRequest = HttpContextUtils.getHttpServletRequest();
        String token = httpServletRequest.getHeader(Constant.HTTP_HEADER);
        String userId = null;
        String userName = null;
        if (StringUtils.hasLength(token)) {
            try {
                userId = JwtUtil.getClaim(token, Constant.USERID);
                userName = JwtUtil.getClaim(token, Constant.USERNAME);
            }
            catch (Exception e) {
                log.error("Exception:", e);
            }
        }
        String ipAddr = IpUtils.getIpAddr(httpServletRequest);

        // 判断操作类型
        String methodName = joinPoint.getSignature().getName();
        String type = "";
        if (methodName.startsWith("update")) {
            type = "update";
        }
        else if (methodName.startsWith("insert")) {
            type = "create";
        }
        else if (methodName.startsWith("delete") || methodName.startsWith("fakeDelete")) {
            type = "delete";
        }


        // 组装操作结果
        StringBuilder sb = new StringBuilder();
        String userNameTemp = userName != null ? userName : "";
        switch (type) {
            case "update":
                sb.append("用户-").append(userNameTemp).append("，对表-").append(tableName).append("做了修改");
                break;
            case "create":
                sb.append("用户-").append(userNameTemp).append("，对表-").append(tableName).append("做了新增");
                break;
            case "delete":
                sb.append("用户-").append(userNameTemp).append("，对表-").append(tableName).append("做了逻辑删除");
                break;
            default:
                break;

        }

        Object response = joinPoint.proceed(params);

        int state = 0;
        // 如果是返回值是void的 直接判断成功
        if (response instanceof Void) {
            state = 1;
        }
        if (response instanceof Integer) {
            if ((int) response > 0) {
                state = 1;
            }
        }

        SysOperateLogDTO sysOperateLogDTO = new SysOperateLogDTO();
        sysOperateLogDTO.setIp(ipAddr);
        sysOperateLogDTO.setResult(sb.toString());
        sysOperateLogDTO.setTargetTable(tableName);
        sysOperateLogDTO.setType(type);
        sysOperateLogDTO.setUserId(userId);
        sysOperateLogDTO.setState(state);

        sysOperateLogMapper.insert(sysOperateLogDTO);
        log.info(sb.toString());
        return response;
    }

    /**
     * 组装详细结果
     */
//    private String getDetailResult(Object[] params, String methodName){
//        StringBuilder sb = new StringBuilder();
//        switch (methodName){
//            case "insert":
//            case "updateById":
//                Object dto = params[0];
//            case "update":
////            case "deleteById":
////            case "delete":
////            case "deleteBatchIds":
////            case "deleteByMap":
////
////
////        }
////        return null
////
////    }
    private String getTableName(String className) {
        if (StringUtils.hasLength(className)) {
            String temp = className.replace("Mapper", "");
            StringBuilder result = new StringBuilder();
            for (int i = 0; i < temp.length(); i++) {
                char ch = temp.charAt(i);
                if (Character.isUpperCase(ch)) {
                    if (i == 0) {
                        result.append(Character.toLowerCase(ch));
                    }
                    else {
                        result.append('_').append(Character.toLowerCase(ch));
                    }

                }
                else {
                    result.append(ch);
                }
            }
            return result.toString();
        }
        return "";
    }

}
